package com.chenfan.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

import static org.springframework.beans.BeanUtils.copyProperties;

/**
 * @author: weishili
 */
@Slf4j
public class CopyUtil {

    private static final ConcurrentHashMap<String, BeanCopier> CACHE_COPIER_MAP = new ConcurrentHashMap<>();

    /**
     * 复制对象属性
     *
     * @param srcObj    源对象
     * @param targetObj 目标对象
     * @param converter converter转换器
     */
    public static <T> T copyObject(Object srcObj, T targetObj, Converter converter) {
        if (null == srcObj) {
            log.error("复制对象时源对象为null!");
            return null;
        }

        if (null == targetObj) {
            log.error("复制对象时目标对象为null!");
            return null;
        }
        BeanCopier bc = getBeanCopierInstance(srcObj.getClass(), targetObj.getClass(), converter);
        bc.copy(srcObj, targetObj, converter);
        return targetObj;
    }

    @Deprecated
    public static <T> T copy(Object srcObj, T targetObj, Converter converter) {
        if (null == srcObj) {
            log.error("复制对象时源对象为null!");
            return null;
        }

        if (null == targetObj) {
            log.error("复制对象时目标对象为null!");
            return null;
        }
        BeanCopier bc = BeanCopier.create(srcObj.getClass(), targetObj.getClass(), converter != null);
        bc.copy(srcObj, targetObj, converter);
        return targetObj;
    }

    /**
     * 复制对象属性
     *
     * @param srcObj    源对象
     * @param targetObj 目标对象
     */
    public static <T> T copyObject(Object srcObj, T targetObj) {
        return copyObject(srcObj, targetObj, null);
    }

    /**
     * 复制对象属性
     *
     * @param srcObj 源对象
     */
    public static <T> T copyObject(Object srcObj, Class<T> targetElementClass) {
        if (srcObj == null || targetElementClass == null) {
            return null;
        }
        try {
            T targetObj = targetElementClass.newInstance();
            return copyObject(srcObj, targetObj, null);
        } catch (Exception e) {
            throw new IllegalArgumentException(String.format("Cannot instantiate an object of %s.", targetElementClass));
        }
    }

    private static <S, T> BeanCopier getBeanCopierInstance(Class<S> sourceClass, Class<T> targetClass, Converter converter) {
        String key = sourceClass.getName() + "#" + targetClass.getName();
        BeanCopier bc = CACHE_COPIER_MAP.get(key);
        if (null == bc) {
            bc = BeanCopier.create(sourceClass, targetClass, converter != null);
            CACHE_COPIER_MAP.put(key, bc);
        }
        return bc;
    }

    /**
     * 集合数据的拷贝
     *
     * @param sources: 数据源类
     * @param target:  目标类::new(eg: UserVO::new)
     * @return
     */
    public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target) {
        return copyListProperties(sources, target, null);
    }

    /**
     * 带回调函数的集合数据的拷贝（可自定义字段拷贝规则）
     *
     * @param sources:  数据源类
     * @param target:   目标类::new(eg: UserVO::new)
     * @param callBack: 回调函数
     * @return
     */
    public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target, BeanCopyUtilCallBack<S, T> callBack) {
        List<T> list = new ArrayList<>(sources.size());
        for (S source : sources) {
            T t = target.get();
            copyProperties(source, t);
            list.add(t);
            if (callBack != null) {
                // 回调
                callBack.callBack(source, t);
            }
        }
        return list;
    }

    @FunctionalInterface
    public interface BeanCopyUtilCallBack<S, T> {
        /**
         * 定义默认回调方法
         *
         * @param t
         * @param s
         */
        void callBack(S t, T s);
    }
}


